﻿
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;

using System.Reflection;

namespace Anno.DynamicApi
{
    /// <summary>
    /// 接口执行者 base
    /// </summary>
    public abstract class BaseExecutor
    {
        protected readonly ILogService logService;
        public BaseExecutor(ApiInfo apiInfo, ExecutorType pointType)
        {
            ExecType = pointType;
            //Name = ExecType.ToString();
            Name = ExecType.ToString() + "_" + Guid.NewGuid().ToString().Replace("-", "");

            ApiInfo = apiInfo;

            logService = Loader.IocLoader.Resolve<ILogService>();
        }
        /// <summary>
        /// 接口定义信息
        /// </summary>
        public ApiInfo ApiInfo { get; }
        /// <summary>
        /// 执行者名称
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 执行者类型
        /// </summary>
        public virtual ExecutorType ExecType { get; set; }
        /// <summary>
        /// 下个执行者节点
        /// </summary>
        //public BaseExecutor NextExecutor { get; set; }
        /// <summary>
        /// 下个执行者集合
        /// </summary>
        public List<BaseExecutor> NextExecutors { get; set; }
        /// <summary>
        /// 入参集合
        /// </summary>
        public List<ApiFieldInfo> ApiInputInfoList { get; set; }

        /// <summary>
        /// 接口执行者调用条件集合
        /// </summary>
        public ExecConditions  Conditions { get; set; }

        /// <summary>
        /// 接口入参类型名称,动态生成 类时用
        /// </summary>
        public string InputClassName { get { return Name + "_Input"; } }
        /// <summary>
        /// 接口是否有入参
        /// </summary>
        public bool HasInput { get { return ApiInputInfoList?.Count > 0; } }
        public string CodeField { get; set; } = "Code";
        public string CodeSucceedValue { get; set; } = "0";
        public string MsgField { get; set; } = "Msg";
        public string DataField { get; set; } = "Data";

        public bool UseExecutorLog { get; set; } = true;
        public BaseExecutor(System.Xml.XmlNode xmlNode, ApiInfo apiInfo, ExecutorType pointType) : this(apiInfo, pointType)
        {
            if (xmlNode == null || apiInfo == null || xmlNode.NodeType == System.Xml.XmlNodeType.Comment)
            {
                return;
            }
            Init(xmlNode, apiInfo);
        }		
        public BaseExecutor(Newtonsoft.Json.Linq.JToken xmlNode, ApiInfo apiInfo, ExecutorType pointType) : this(apiInfo, pointType)
        {
            if (xmlNode == null || apiInfo == null)
            {
                return;
            }
            Init(xmlNode, apiInfo);
        }
        public virtual void Init(System.Xml.XmlNode ExecutorNode, ApiInfo apiInfo)
        {
            try
            {
                if (ExecutorNode == null || apiInfo == null || ExecutorNode.NodeType == System.Xml.XmlNodeType.Comment)
                {
                    return;
                }
                CodeField = ExecutorNode.GetXmlNodeAttributeValue("CodeField", "Code");
                CodeSucceedValue = ExecutorNode.GetXmlNodeAttributeValue("CodeSucceedValue", "0");
                MsgField = ExecutorNode.GetXmlNodeAttributeValue("MsgField", "Msg");
                DataField = ExecutorNode.GetXmlNodeAttributeValue("DataField", "data");

                UseExecutorLog = ExecutorNode.GetXmlNodeAttributeValue("UseExecutorLog"
                    , PubFun.GetAppSettings("UseExecutorLog", "false")).ToBool_();
            }
            catch { }
        }
        public virtual void Init(Newtonsoft.Json.Linq.JToken ExecutorNode, ApiInfo apiInfo)
        {
            try
            {
                if (ExecutorNode == null || apiInfo == null)
                {
                    return;
                }
                //Name = ExecutorNode.GetXmlNodeAttributeValue("Name");
                CodeField = ExecutorNode.GetXmlNodeAttributeValue("CodeField", "ResponseCode");
                CodeSucceedValue = ExecutorNode.GetXmlNodeAttributeValue("CodeSucceedValue", "AA");
                MsgField = ExecutorNode.GetXmlNodeAttributeValue("MsgField", "ResponseDesc");
                DataField = ExecutorNode.GetXmlNodeAttributeValue("DataField", "data");

                UseExecutorLog = ExecutorNode.GetXmlNodeAttributeValue("UseExecutorLog"
                    , PubFun.GetAppSettings("UseExecutorLog", "false")).ToBool_();
            }
            catch { }
        }
        //---------------------------------------------------------------------------------------------------------------------------------
        protected IDictionary<string, string> headers = null;
        /// <summary>
        /// 执行者
        /// </summary>
        /// <returns></returns>
        public virtual object ApiExecutor(ApiInfo apiInfo, object input)
        {
            dynamic rets = new object();
            try
            {
                if (null != input && input is Dictionary<string, string> dicInput)
                {
                    if (dicInput.TryGetValue("Request.Headers", out var headerstr) && !string.IsNullOrWhiteSpace(headerstr))
                    {
                        headers = headerstr.DeserializeObjectByJson<Dictionary<string, string>>();
                    }
                }
                //headers = PubFun.GetDicHeaders(request);

                rets = Executor(input);

                #region 执行下级执行者
                if (this.NextExecutors?.Count > 0)
                {
                    var comps = this.NextExecutors?.FindAll(f => f.Conditions.IsMatch(rets.OutputData));
                    if (comps?.Count > 0)
                    {
                        var returnList = new List<object>();
                        if (rets.OutputData != null)
                            returnList.Add(new { Executor = "" + this.ExecType, Result = rets.OutputData });

                        comps.ForEach(comp =>
                        {
                            if (comp == null)
                            {
                                return;
                            }
                            //--------------------------------------------------------------------------------------------------------------------------------------------------------------------
                            dynamic ReturnObj = comp.ApiExecutor(apiInfo, rets.OutputData);
                            if (ReturnObj == null || ReturnObj.OutputData == null)
                            {
                                Log.Log.Error(apiInfo.KeyWord + $"{comp.ExecType},调用失败.");
                                returnList.Add(new { Executor = "" + comp.ExecType, Result = $"调用失败,{ReturnObj.Msg}" });
                                return;
                            }
                            returnList.Add(new { Executor = "" + comp.ExecType, Result = ReturnObj.OutputData });
                        });
                        rets = ApiResult.Success(returnList);
                    }
                }
                #endregion

                if (UseExecutorLog)
                {
                    ExecutorLog(apiInfo
                       , $"{apiInfo.HttpMethod}@({apiInfo.Title}) {apiInfo.Route}//{this.ToString()}", input, rets, null);
                }
                return rets;
            }
            catch (System.Exception ex)
            {
                ExecutorLog(apiInfo
                        , $"{apiInfo.HttpMethod}@({apiInfo.Title}) {apiInfo.Route}//{this.ToString()}", input, rets, ex);
                var error = ex.GetExceptionMessage();
                Log.Log.Error(error);
                return ApiResult.Exception(ex);
            }
        }
        protected virtual void ExecutorLog(ApiInfo apiInfo, string msg, object input, object response, System.Exception ex)
        {
            try
            {
                var properties = new Dictionary<string, object>();
                //properties["名称"] = apiInfo.ApiName;
                //properties["标题"] = apiInfo.Title;
                properties["请求方法"] = apiInfo.HttpMethod;
                //properties["请求路径"] = apiInfo.Route;// request.HttpRequest.Path;//.Value;
                //properties["接口信息"] = $"{apiInfo.ToString()}";
                properties["消息头"] = headers;
                properties["请求消息"] = input;
                properties["响应消息"] = response;
                //properties["内容"] = msg;
                //properties["Tags"] = level;
                if (ex != null) properties["Exception"] = ex.ToString();

                var msgobj = JsonHelper.SerializeObjectToJson(properties);
                if (ex == null)
                    Log.Log.Fatal(msgobj, this.GetType());
                else
                    Log.Log.Error(ex, msgobj, this.GetType());
                if (null != input && input is Dictionary<string, string> dicInput)
                {
                    var traceId = dicInput.RequestString("TraceId");
                    var uName = dicInput.RequestString("uname");
                    if (string.IsNullOrWhiteSpace(uName))
                        uName = "DynamicApi";
                    if (ex == null)
                    {
                        logService.Info(msgobj, traceId, uName, apiInfo.Title);
                    }
                    else
                    {
                        logService.Error(msgobj, traceId, uName, apiInfo.Title);
                    }
                }
                //WindowsService.Log.Log.Critical(msg);
            }
            catch (System.Exception ex1)
            {
                var error = ex1.GetExceptionMessage();
                Log.Log.Error(error);
            }
        }
        /// <summary>
        /// 执行者
        /// </summary>
        /// <returns></returns>
        protected virtual object Executor(object input)
        {
            return null;
        }

        /// <summary>
        /// 返回结果处理
        /// </summary>
        /// <param name="jsret"></param>
        /// <returns></returns>
        protected virtual ApiResult getJsonResult(object jsret)
        {
            var rets = new ApiResult();
            if (jsret is Newtonsoft.Json.Linq.JObject || jsret is System.Dynamic.ExpandoObject
                || jsret is System.Collections.Generic.Dictionary<string, object>)
            {
                var restcodeval = PubFun.GetFieldPathValue(jsret, CodeField, null, "-1").NullToStr();
                rets.Status = (restcodeval.Trim().ToLower() == CodeSucceedValue.Trim().ToLower() ? "0" : restcodeval.IsNullOrEmpty() ? "500" : restcodeval.NullToStr()).ToInt_()==0;
                rets.Msg = PubFun.GetFieldPathValue(jsret, MsgField, null, "").NullToStr();
                rets.OutputData = PubFun.GetFieldPathValue(jsret, DataField, null, jsret);
            }
            else
            {
                rets.Status = true;
                rets.Msg = "";

                rets.OutputData = jsret;
            }
            return rets;
        }
        /// <summary>
        /// 消除缓存方法
        /// </summary>
        public virtual void RemoveCache()
        {
        }
        public override string ToString()
        {
            return Name;
        }

        /// <summary>
        /// 返回JSON对象
        /// </summary>
        public virtual object JObject
        {
            get
            {
                var dyret = DicAttrs;

                var nextExecutors = new List<object>();
                NextExecutors?.ForEach(ext => nextExecutors.Add(ext.JObject));

                var apiInputInfoList = new List<object>();
                ApiInputInfoList?.ForEach(ext => apiInputInfoList.Add(ext.JObject));

                dyret["NextExecutors"] = nextExecutors;
                dyret["ApiInputInfoList"] = apiInputInfoList;

                dyret["HasInput"] = HasInput;

                return dyret;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual IDictionary<string, object> DicAttrs
        {
            get
            {
                var ret = new System.Dynamic.ExpandoObject();
                IDictionary<string, object> dyret = ret;

                //var nextExecutors = new List<IDictionary<string, object>>();
                //NextExecutors?.ForEach(ext => nextExecutors.Add(ext.DicAttrs));

                //var apiInputInfoList = new List<System.Collections.Generic.IDictionary<string, object>>();
                //ApiInputInfoList?.ForEach(ext => apiInputInfoList.Add(ext.DicAttrs));

                dyret["Name"] = Name;
                dyret["ExecType"] = ExecType.ToString();
                dyret["CodeField"] = CodeField;
                dyret["CodeSucceedValue"] = CodeSucceedValue;
                dyret["MsgField"] = MsgField;
                dyret["DataField"] = DataField;
                dyret["UseExecutorLog"] = UseExecutorLog;
                //dyret["NextExecutors"] = nextExecutors;
                //dyret["ApiInputInfoList"] = apiInputInfoList;
                dyret["Conditions"] = Conditions.DicAttrs;

                //dyret["HasInput"] = HasInput;

                return ret;
            }
        }
    }
}
